package com.yu.dv.autoconfigure;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yu.dv.autoconfigure.properties.DashScopeProperties;
import com.yu.dv.entity.SqlTransferException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class DashScopeClient {

    private final String apiKey;
    private final String model;
    private final String endpoint;
    private final HttpClient httpClient;
    private final ObjectMapper objectMapper;

    public DashScopeClient(DashScopeProperties properties) {
        this.apiKey = properties.getApiKey();
        this.model = properties.getModel();
        this.endpoint = properties.getEndpoint();
        this.httpClient = HttpClients.createDefault();
        this.objectMapper = new ObjectMapper();
    }

    public String generateSql(String prompt) {
        long startTime = System.currentTimeMillis();

        try {
            String requestBody = buildOpenAICompatibleRequest(prompt);
            HttpPost httpPost = new HttpPost(endpoint);

            httpPost.setHeader("Authorization", "Bearer " + apiKey);
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setHeader("Accept", "application/json");
            httpPost.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));

            log.info("调用通义大模型API（OpenAI兼容模式）");
            log.info("请求URL: {}", endpoint);
            log.debug("请求体: {}", requestBody);

            HttpResponse response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            HttpEntity entity = response.getEntity();

            String responseBody = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            log.info("API响应状态码: {}", statusCode);
            log.debug("API响应体: {}", responseBody);

            if (statusCode != 200) {
                log.error("API调用失败，状态码: {}, 响应: {}", statusCode, responseBody);
                throw new SqlTransferException("API调用失败，状态码: " + statusCode + ", 响应: " + responseBody);
            }

            return parseOpenAIResponse(responseBody);

        } catch (Exception e) {
            log.error("调用通义大模型失败，耗时: {}ms", System.currentTimeMillis() - startTime, e);
            throw new SqlTransferException("调用通义大模型失败: " + e.getMessage());
        }
    }

    private String buildOpenAICompatibleRequest(String prompt) {
        try {
            Map<String, Object> requestMap = new HashMap<>();
            requestMap.put("model", model);
            requestMap.put("stream", false);
            requestMap.put("max_tokens", 500);

            List<Map<String, String>> messages = new ArrayList<>();
            Map<String, String> message = new HashMap<>();
            message.put("role", "user");
            message.put("content", prompt);
            messages.add(message);

            requestMap.put("messages", messages);
            return objectMapper.writeValueAsString(requestMap);

        } catch (Exception e) {
            return String.format(
                    "{" +
                            "\"model\": \"%s\"," +
                            "\"messages\": [{\"role\": \"user\", \"content\": \"%s\"}]," +
                            "\"stream\": false," +
                            "\"max_tokens\": 500" +
                            "}",
                    model, escapeJson(prompt)
            );
        }
    }

    private String parseOpenAIResponse(String responseBody) {
        try {
            JsonNode jsonNode = objectMapper.readTree(responseBody);
            log.info("解析响应JSON: {}", jsonNode.toString());

            if (jsonNode.has("error")) {
                JsonNode error = jsonNode.get("error");
                String errorMessage = error.has("message") ?
                        error.get("message").asText() : "未知错误";
                throw new SqlTransferException("API返回错误: " + errorMessage);
            }

            if (jsonNode.has("choices") && jsonNode.get("choices").isArray() &&
                    jsonNode.get("choices").size() > 0) {

                JsonNode choice = jsonNode.get("choices").get(0);
                if (choice.has("message") && choice.get("message").has("content")) {
                    String content = choice.get("message").get("content").asText();
                    log.info("AI生成内容: {}", content);
                    return content.trim();
                }
            }

            if (jsonNode.has("text")) {
                String text = jsonNode.get("text").asText();
                log.info("AI生成内容: {}", text);
                return text.trim();
            }

            log.warn("无法解析标准响应格式，返回原始响应文本");
            return responseBody;

        } catch (Exception e) {
            throw new SqlTransferException("解析API响应失败: " + e.getMessage());
        }
    }

    private String escapeJson(String text) {
        if (text == null) {
            return "";
        }
        return text.replace("\\", "\\\\")
                .replace("\"", "\\\"")
                .replace("\b", "\\b")
                .replace("\f", "\\f")
                .replace("\n", "\\n")
                .replace("\r", "\\r")
                .replace("\t", "\\t");
    }

    public String generateSqlFromNaturalLanguage(String naturalLanguage, String tableSchema) {
        try {
            String prompt = buildSqlGenerationPrompt(naturalLanguage, tableSchema);
            return generateSql(prompt);
        } catch (Exception e) {
            throw new SqlTransferException("SQL生成失败: " + e.getMessage());
        }
    }

    private String buildSqlGenerationPrompt(String naturalLanguage, String tableSchema) {
        StringBuilder prompt = new StringBuilder();
        prompt.append("你是一个专业的SQL生成助手。请将自然语言描述转换为标准的SQL DDL语句。\n\n");

        if (tableSchema != null && !tableSchema.trim().isEmpty()) {
            prompt.append("相关表结构信息：\n").append(tableSchema).append("\n\n");
        }

        prompt.append("自然语言描述：").append(naturalLanguage).append("\n\n");
        prompt.append("要求：\n");
        prompt.append("1. 只返回SQL语句，不要包含任何解释或额外文本\n");
        prompt.append("2. 确保SQL语法正确\n");
        prompt.append("3. 使用标准的SQL语法\n");
        prompt.append("4. 如果有主键，请明确指定PRIMARY KEY\n\n");
        prompt.append("SQL语句：");
        return prompt.toString();
    }

    public String generateSqlWithRetry(String prompt, int maxRetries) {
        for (int i = 0; i < maxRetries; i++) {
            try {
                return generateSql(prompt);
            } catch (Exception e) {
                log.warn("第{}次调用失败: {}", i + 1, e.getMessage());

                if (i < maxRetries - 1) {
                    try {
                        long sleepTime = 1000L * (i + 1);
                        Thread.sleep(sleepTime);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw new SqlTransferException("重试被中断");
                    }
                }
            }
        }
        throw new SqlTransferException("重试" + maxRetries + "次后仍然失败");
    }
}